import * as fs from 'fs';
import * as path from 'path';
import { EnvironmentDetector } from './modules/environmentDetector';

// 测试输出目录
const TEST_OUTPUT_DIR = path.join(__dirname, '../test-output');

// 确保测试输出目录存在
if (!fs.existsSync(TEST_OUTPUT_DIR)) {
    fs.mkdirSync(TEST_OUTPUT_DIR, { recursive: true });
}

// 本地定义日志类型，避免依赖vscode
enum LogType {
    ACCESS = 'access',
    ERROR = 'error',
    ALL = 'all'
}

// 模拟日志条目类型
interface LogEntry {
    timestamp: Date;
    type: LogType;
    message: string;
    level?: string;
    statusCode?: number;
    path?: string;
    ip?: string;
    method?: string;
    configPath?: string;
    lineNumber?: number;
}

// 模拟日志分析结果
interface LogAnalysisResult {
    totalEntries: number;
    accessCount: number;
    errorCount: number;
    statusCodeCounts: { [key: string]: number };
    topIps: { ip: string, count: number }[];
    topPaths: { path: string, count: number }[];
    errorsByFile: { [key: string]: { count: number, lines: number[] } };
}

/**
 * 创建模拟日志数据
 */
function createMockLogs(): LogEntry[] {
    const logs: LogEntry[] = [];
    const now = new Date();
    
    // 模拟访问日志
    for (let i = 0; i < 50; i++) {
        const time = new Date(now.getTime() - Math.random() * 24 * 60 * 60 * 1000);
        const statusCodes = [200, 200, 200, 200, 301, 302, 404, 500];
        const statusCode = statusCodes[Math.floor(Math.random() * statusCodes.length)];
        const paths = ['/', '/index.html', '/about.html', '/api/data', '/images/logo.png', '/css/style.css'];
        const path = paths[Math.floor(Math.random() * paths.length)];
        const ips = ['192.168.1.1', '192.168.1.2', '10.0.0.1', '172.16.0.1', '127.0.0.1'];
        const ip = ips[Math.floor(Math.random() * ips.length)];
        
        logs.push({
            timestamp: time,
            type: LogType.ACCESS,
            message: `${ip} - - [${time.toISOString()}] "GET ${path} HTTP/1.1" ${statusCode} 2048 "-" "Mozilla/5.0"`,
            statusCode,
            path,
            ip,
            method: 'GET'
        });
    }
    
    // 模拟错误日志
    const configPaths = [
        path.join(TEST_OUTPUT_DIR, 'test-nginx.conf'),
        path.join(TEST_OUTPUT_DIR, 'invalid-nginx.conf')
    ];
    
    // 确保测试配置文件存在
    if (!fs.existsSync(configPaths[0])) {
        fs.writeFileSync(configPaths[0], `
server {
    listen 8080;
    server_name test.local;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}
`);
    }
    
    if (!fs.existsSync(configPaths[1])) {
        fs.writeFileSync(configPaths[1], `
server {
    listen 8080;
    server_name test.local;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    # 故意缺少右花括号
}
`);
    }
    
    const errorTypes = [
        { 
            message: `directive "server" has no opening "{" in ${configPaths[1]}:10`, 
            configPath: configPaths[1], 
            lineNumber: 10 
        },
        { 
            message: `open() "${path.join(TEST_OUTPUT_DIR, 'missing.conf')}" failed (2: No such file or directory)`, 
            configPath: path.join(TEST_OUTPUT_DIR, 'missing.conf'), 
            lineNumber: undefined 
        },
        { 
            message: `unexpected "}" in ${configPaths[0]}:5`, 
            configPath: configPaths[0], 
            lineNumber: 5 
        }
    ];
    
    for (let i = 0; i < 20; i++) {
        const time = new Date(now.getTime() - Math.random() * 24 * 60 * 60 * 1000);
        const errorType = errorTypes[Math.floor(Math.random() * errorTypes.length)];
        const levels = ['emerg', 'alert', 'crit', 'error', 'warn', 'notice', 'info', 'debug'];
        const level = levels[Math.floor(Math.random() * levels.length)];
        
        logs.push({
            timestamp: time,
            type: LogType.ERROR,
            message: errorType.message,
            level,
            configPath: errorType.configPath,
            lineNumber: errorType.lineNumber
        });
    }
    
    // 按时间排序
    return logs.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
}

/**
 * 分析模拟日志数据
 */
function analyzeMockLogs(logs: LogEntry[]): LogAnalysisResult {
    // 初始化分析结果
    const result: LogAnalysisResult = {
        totalEntries: logs.length,
        accessCount: 0,
        errorCount: 0,
        statusCodeCounts: {},
        topIps: [],
        topPaths: [],
        errorsByFile: {}
    };

    // IP和路径计数
    const ipCounts: { [key: string]: number } = {};
    const pathCounts: { [key: string]: number } = {};
    
    // 处理每个日志条目
    for (const entry of logs) {
        // 根据类型分类
        if (entry.type === LogType.ACCESS) {
            result.accessCount++;
            
            // 统计状态码
            if (entry.statusCode) {
                const statusGroup = Math.floor(entry.statusCode / 100) * 100;
                const statusKey = `${statusGroup}`;
                result.statusCodeCounts[statusKey] = (result.statusCodeCounts[statusKey] || 0) + 1;
            }
            
            // 统计IP
            if (entry.ip) {
                ipCounts[entry.ip] = (ipCounts[entry.ip] || 0) + 1;
            }
            
            // 统计路径
            if (entry.path) {
                pathCounts[entry.path] = (pathCounts[entry.path] || 0) + 1;
            }
        } else if (entry.type === LogType.ERROR) {
            result.errorCount++;
            
            // 统计错误的配置文件和行号
            if (entry.configPath) {
                if (!result.errorsByFile[entry.configPath]) {
                    result.errorsByFile[entry.configPath] = { count: 0, lines: [] };
                }
                result.errorsByFile[entry.configPath].count++;
                
                if (entry.lineNumber) {
                    result.errorsByFile[entry.configPath].lines.push(entry.lineNumber);
                }
            }
        }
    }
    
    // 计算 top IPs
    result.topIps = Object.entries(ipCounts)
        .map(([ip, count]) => ({ ip, count }))
        .sort((a, b) => b.count - a.count)
        .slice(0, 10);
        
    // 计算 top paths
    result.topPaths = Object.entries(pathCounts)
        .map(([path, count]) => ({ path, count }))
        .sort((a, b) => b.count - a.count)
        .slice(0, 10);
    
    return result;
}

/**
 * 生成分析报告
 */
function generateReport(result: LogAnalysisResult): string {
    let report = '# Nginx 日志分析报告\n\n';
    
    // 基本统计
    report += '## 基本统计\n\n';
    report += `- 总日志条目: ${result.totalEntries}\n`;
    report += `- 访问日志: ${result.accessCount}\n`;
    report += `- 错误日志: ${result.errorCount}\n\n`;
    
    // HTTP状态码分布
    report += '## HTTP状态码分布\n\n';
    for (const [code, count] of Object.entries(result.statusCodeCounts).sort()) {
        report += `- ${code}: ${count} 次 (${percentage(count, result.accessCount)}%)\n`;
    }
    report += '\n';
    
    // 访问量最高的IP
    if (result.topIps.length > 0) {
        report += '## 访问量最高的IP\n\n';
        for (const ip of result.topIps) {
            report += `- ${ip.ip}: ${ip.count} 次 (${percentage(ip.count, result.accessCount)}%)\n`;
        }
        report += '\n';
    }
    
    // 访问量最高的路径
    if (result.topPaths.length > 0) {
        report += '## 访问量最高的路径\n\n';
        for (const path of result.topPaths) {
            report += `- ${path.path}: ${path.count} 次 (${percentage(path.count, result.accessCount)}%)\n`;
        }
        report += '\n';
    }
    
    // 错误分布
    if (Object.keys(result.errorsByFile).length > 0) {
        report += '## 错误分布\n\n';
        for (const [file, error] of Object.entries(result.errorsByFile)) {
            report += `- ${file}: ${error.count} 错误`;
            if (error.lines.length > 0) {
                const uniqueLines = [...new Set(error.lines)].sort((a, b) => a - b);
                report += ` (行: ${uniqueLines.join(', ')})`;
            }
            report += '\n';
        }
        report += '\n';
    }
    
    return report;
}

/**
 * 计算百分比
 */
function percentage(part: number, total: number): number {
    if (total === 0) return 0;
    return Math.round((part / total) * 100 * 10) / 10;
}

/**
 * 测试日志查看器和分析器
 */
async function testLogModules() {
    console.log('========== 开始测试日志与调试模块 ==========\n');
    
    // 1. 测试环境检测
    console.log('----- 测试环境检测 -----');
    const detector = new EnvironmentDetector();
    const environment = await detector.detect();
    console.log(`检测到环境: ${JSON.stringify(environment)}`);
    
    // 2. 创建模拟日志
    console.log('\n----- 创建模拟日志数据 -----');
    const mockLogs = createMockLogs();
    console.log(`创建了 ${mockLogs.length} 条模拟日志条目`);
    
    // 3. 测试日志分析
    console.log('\n----- 测试日志分析 -----');
    const analysisResult = analyzeMockLogs(mockLogs);
    
    console.log('日志分析结果:');
    console.log(`- 总日志条目: ${analysisResult.totalEntries}`);
    console.log(`- 访问日志数: ${analysisResult.accessCount}`);
    console.log(`- 错误日志数: ${analysisResult.errorCount}`);
    
    console.log('\nHTTP状态码分布:');
    for (const [code, count] of Object.entries(analysisResult.statusCodeCounts)) {
        console.log(`- ${code}: ${count} 次`);
    }
    
    console.log('\n访问量最高的IP:');
    for (const ip of analysisResult.topIps.slice(0, 3)) {
        console.log(`- ${ip.ip}: ${ip.count} 次`);
    }
    
    console.log('\n访问量最高的路径:');
    for (const path of analysisResult.topPaths.slice(0, 3)) {
        console.log(`- ${path.path}: ${path.count} 次`);
    }
    
    console.log('\n错误分布:');
    for (const [file, error] of Object.entries(analysisResult.errorsByFile)) {
        console.log(`- ${file}: ${error.count} 错误`);
    }
    
    // 4. 测试生成报告
    console.log('\n----- 测试生成日志报告 -----');
    const report = generateReport(analysisResult);
    const reportPath = path.join(TEST_OUTPUT_DIR, 'log-analysis-report.md');
    fs.writeFileSync(reportPath, report);
    console.log(`已生成日志分析报告: ${reportPath}`);
    
    console.log('\n========== 日志与调试模块测试完成 ==========');
}

// 运行测试
testLogModules().catch(error => {
    console.error('测试失败:', error);
}); 